﻿//
// name    Victor86B_usbDMM.cpp
// author  david moloney, movidius ltd.
// purpose decodes and displays output from Victor 86B USB DMM
// date    03 Jan 2012
// note    based on HIDAPI http://www.signal11.us/oss/hidapi/
//

#pragma warning(disable : 4996) // disable MSVC++ printf warning

#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include "hidapi.h"
#include "time.h"


/* Victor 86B DMM on my machine returns following descriptor

  Device Found
  type: 1244 d237
  path: \\?\hid#vid_1244&pid_d237#9&29fd82b3&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
  serial_number:
  Manufacturer:
  Product:
  Release:      100
  Interface:    -1
*/

void report_HIDs() {

	struct hid_device_info *devs, *cur_dev;
	
	devs = hid_enumerate(0x0, 0x0);
	cur_dev = devs;	
	while (cur_dev) {
		printf("Device Found\n  type: %04hx %04hx\n  path: %s\n  serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
		printf("\n");

		if (cur_dev->vendor_id==0x1244) printf("  Manufacturer: Victor\n");
		else                            printf("  Manufacturer: %ls\n", cur_dev->manufacturer_string);
		
		if (cur_dev->product_id==0xd237) printf("  Product:      86B DMM\n");
		else                             printf("  Product:      %ls\n", cur_dev->product_string);
		
		printf("  Release:      %hx\n", cur_dev->release_number);
		printf("  Interface:    %d\n",  cur_dev->interface_number);
		printf("\n");
		cur_dev = cur_dev->next;
	}
	hid_free_enumeration(devs);

} // report_HIDs()


struct Victor86B_display { // Victor 86B LCD Display descriptor
  /*

  AUTO RS232 REL HOLD BATT

  DC  -   -   -   -
  AC | | | | | | | |  % C
   -  -   -   -   -   < >
     | | | | | | | |  n m F V A  
	  - . - . - . -     μ
	                  M k Ω Hz        
  */

  int digit[4], decimal[4], minus;
  int AUTO, RS232, REL, HOLD, BATT;
  int AC, DC;
  int Percent, degC;
  int Spkr, Diode;
  int nano, milli, Farads, V, A;
  int       micro;
  int Mega, Kilo, Ohms, Hertz;
  int Overload;

}; // struct Victor86B_display


struct DMM_reading { // DMM_reading
  double value; // value of reading
  int    units; // Volts, Amps, oC etc.
  int    info;  // Overload, REL, HOLD etc.
}; // struct DMM_reading


struct DMM_reading decode_Victor86B(unsigned char* buf) {

  // Victor86B multimeter LCD control bits passed back as a string of 14 hex characters
  // details derived experimentally using the Victor86B DMM and a Bench PSU

  struct DMM_reading DMM;

  int LCD_minus=0;
  int LCD_digit[4];
  int LCD_decimal[4];
  int LCD_DC   = 0; // DC
  int LCD_AC   = 0; // AC
  int LCD_V    = 0; // Volts
  int LCD_A    = 0; // Amps
  int LCD_m    = 0; // m - milliamps
  int LCD_u    = 0; // u - microamps
  int LCD_REL  = 0; // REL
  int LCD_HOLD = 0; // HOLD
  int LCD_Hz   = 0; // Hz
  int LCD_oC   = 0; // degrees C
  int LCD_M    = 0; // Mega - ohms  
  int LCD_OL   = 0; // Overload

  if (strlen((char*)buf)!=23) { // display error message if USB HID packet (buf) incomplete!
	//
	printf("no string read from DMM ... %d\n",strlen((char*)buf));
	printf("  1. make sure DMM is switched on\n");
	printf("  2. try plugging out USB and replacing\n");
	DMM.info = -1;
	return DMM;
  }
  else { // decode and display digits from USB HID packet (buf)
    
	// LCD       digits           annunciators
	//        -   -   -   - 
	//       | | | | | | | | 
	//     -  -   -   -   -       M            Hz     
	//       | | | | | | | |   DC REL          V
	//        -   -   -   -    AC HOLD m oC u  A
	//
	// buf  3,10 6,9 5,7 0,2   1  4    8 11 12 13

    // reset display variables
    LCD_minus=0;
    LCD_digit[0]=LCD_digit[1]=LCD_digit[2]=LCD_digit[3]=0;
    LCD_decimal[0]=LCD_decimal[1]=LCD_decimal[2]=LCD_decimal[3]=0;

    // LCD_digit[3] - most significant digit
  
    /* 
      digit 4 of Victor86B LCD display ... values are decimal!
	                    .
      LCD b3	b10		b10
	  0   33    79      95   
      1   17	111     127
      2   65	15      31
      3   97	239     255
      4   81	175     191
    */

    // +X
    if ((unsigned)buf[3]== 33 && (unsigned)buf[10]== 79) LCD_digit[3]=0;
    if ((unsigned)buf[3]== 17 && (unsigned)buf[10]==111) LCD_digit[3]=1;
    if ((unsigned)buf[3]== 65 && (unsigned)buf[10]== 15) LCD_digit[3]=2;
    if ((unsigned)buf[3]== 97 && (unsigned)buf[10]==239) LCD_digit[3]=3;
    if ((unsigned)buf[3]== 81 && (unsigned)buf[10]==175) LCD_digit[3]=4;
	// -X
	if ((unsigned)buf[3]== 33 && (unsigned)buf[10]== 95) { LCD_digit[3]=0; LCD_minus=1; }
    if ((unsigned)buf[3]== 17 && (unsigned)buf[10]==127) { LCD_digit[3]=1; LCD_minus=1; }
    if ((unsigned)buf[3]== 65 && (unsigned)buf[10]== 31) { LCD_digit[3]=2; LCD_minus=1; }
    if ((unsigned)buf[3]== 97 && (unsigned)buf[10]==255) { LCD_digit[3]=3; LCD_minus=1; }
    if ((unsigned)buf[3]== 81 && (unsigned)buf[10]==191) { LCD_digit[3]=4; LCD_minus=1; }

    // LCD_digit[2]

    /* 
    digit 3 of Victor86B LCD display
                .   
    LCD b6	b9  b9
	0   47  69  85  
    1   31	101 117 
    2   79	5   21  
    3   111	229 245 
    4   95	165 181 
    5   239	37  53  
    6   239	69  85  
    7   31	229 245 
    8   111	69  85  
    9   111	37  53  

	[.] bit 5 of buf[9] controls the decimal-point which preceeds digit 3 of the LCD
    */

    // X
    if ((unsigned)buf[6]== 47 && (unsigned)buf[9]== 69) LCD_digit[2]=0;
    if ((unsigned)buf[6]== 31 && (unsigned)buf[9]==101) LCD_digit[2]=1;
    if ((unsigned)buf[6]== 79 && (unsigned)buf[9]==  5) LCD_digit[2]=2;
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]==229) LCD_digit[2]=3;
    if ((unsigned)buf[6]== 95 && (unsigned)buf[9]==165) LCD_digit[2]=4;
    if ((unsigned)buf[6]==239 && (unsigned)buf[9]== 37) LCD_digit[2]=5;
    if ((unsigned)buf[6]==239 && (unsigned)buf[9]== 69) LCD_digit[2]=6;
    if ((unsigned)buf[6]== 31 && (unsigned)buf[9]==229) LCD_digit[2]=7;
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]== 69) LCD_digit[2]=8; 
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]== 37) LCD_digit[2]=9;
	// .X
	if ((unsigned)buf[6]== 47 && (unsigned)buf[9]== 85) { LCD_digit[2]=0; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]== 31 && (unsigned)buf[9]==117) { LCD_digit[2]=1; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]== 79 && (unsigned)buf[9]== 21) { LCD_digit[2]=2; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]==245) { LCD_digit[2]=3; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]== 95 && (unsigned)buf[9]==181) { LCD_digit[2]=4; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]==239 && (unsigned)buf[9]== 53) { LCD_digit[2]=5; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]==239 && (unsigned)buf[9]== 85) { LCD_digit[2]=6; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]== 31 && (unsigned)buf[9]==245) { LCD_digit[2]=7; LCD_decimal[2]=1; }
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]== 85) { LCD_digit[2]=8; LCD_decimal[2]=1; } 
    if ((unsigned)buf[6]==111 && (unsigned)buf[9]== 53) { LCD_digit[2]=9; LCD_decimal[2]=1; }

    // LCD_digit[1]  
  
    /*          .
    LCD b5	b7  b7
	0   54  84  100
    1   38	116 132
    2   86	20  36
    3   118	244 4
    4   102	180 196
    5   246	52  68
    6   246	84  100
    7   38	244 4
    8   118	84  100
    9   118	52  68
    */

    // X
    if ((unsigned)buf[5]== 54 && (unsigned)buf[7]== 84) LCD_digit[1] =0;
    if ((unsigned)buf[5]== 38 && (unsigned)buf[7]==116) LCD_digit[1] =1;
    if ((unsigned)buf[5]== 86 && (unsigned)buf[7]== 20) LCD_digit[1] =2;
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]==244) LCD_digit[1] =3;
    if ((unsigned)buf[5]==102 && (unsigned)buf[7]==180) LCD_digit[1] =4;
    if ((unsigned)buf[5]==246 && (unsigned)buf[7]== 52) LCD_digit[1] =5;
    if ((unsigned)buf[5]==246 && (unsigned)buf[7]== 84) LCD_digit[1] =6;
    if ((unsigned)buf[5]== 38 && (unsigned)buf[7]==244) LCD_digit[1] =7;
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]== 84) LCD_digit[1] =8;
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]== 52) LCD_digit[1] =9;
	// .X
	if ((unsigned)buf[5]== 54 && (unsigned)buf[7]==100) { LCD_digit[1] =0; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]== 38 && (unsigned)buf[7]==132) { LCD_digit[1] =1; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]== 86 && (unsigned)buf[7]== 36) { LCD_digit[1] =2; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]==  4) { LCD_digit[1] =3; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==102 && (unsigned)buf[7]==196) { LCD_digit[1] =4; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==246 && (unsigned)buf[7]== 68) { LCD_digit[1] =5; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==246 && (unsigned)buf[7]==100) { LCD_digit[1] =6; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]== 38 && (unsigned)buf[7]==  4) { LCD_digit[1] =7; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]==100) { LCD_digit[1] =8; LCD_decimal[1]=1; }
    if ((unsigned)buf[5]==118 && (unsigned)buf[7]== 68) { LCD_digit[1] =9; LCD_decimal[1]=1; }
	//
    if ((unsigned)buf[5]==150 && (unsigned)buf[7]==228) LCD_OL = 1; // O.L Overload
    if ((unsigned)buf[5]==150 && (unsigned)buf[7]==212) LCD_OL = 1; // O.L Overload

    // LCD_digit[0] least significant digit
 
    /*          .
    LCD b0  b2  b0
    0	75	29  91
    1	107	13  123
    2	11	61  27
    3	235	93  251
    4	171	77  187
    5	43	221 59
    6	75	221 91
    7	235	13  251
    8	75	93  91
    9	43	93  59
    */

    // X
    if ((unsigned)buf[0]== 75 && (unsigned)buf[2]== 29) LCD_digit[0]=0;
    if ((unsigned)buf[0]==107 && (unsigned)buf[2]== 13) LCD_digit[0]=1;
    if ((unsigned)buf[0]== 11 && (unsigned)buf[2]== 61) LCD_digit[0]=2;
    if ((unsigned)buf[0]==235 && (unsigned)buf[2]== 93) LCD_digit[0]=3;
    if ((unsigned)buf[0]==171 && (unsigned)buf[2]== 77) LCD_digit[0]=4;
    if ((unsigned)buf[0]== 43 && (unsigned)buf[2]==221) LCD_digit[0]=5;
    if ((unsigned)buf[0]== 75 && (unsigned)buf[2]==221) LCD_digit[0]=6;
    if ((unsigned)buf[0]==235 && (unsigned)buf[2]== 13) LCD_digit[0]=7;
    if ((unsigned)buf[0]== 75 && (unsigned)buf[2]== 93) LCD_digit[0]=8;
    if ((unsigned)buf[0]== 43 && (unsigned)buf[2]== 93) LCD_digit[0]=9;
    // .X
	if ((unsigned)buf[0]== 91 && (unsigned)buf[2]== 29) { LCD_digit[0]=0; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]==123 && (unsigned)buf[2]== 13) { LCD_digit[0]=1; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]== 27 && (unsigned)buf[2]== 61) { LCD_digit[0]=2; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]==251 && (unsigned)buf[2]== 93) { LCD_digit[0]=3; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]==187 && (unsigned)buf[2]== 77) { LCD_digit[0]=4; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]== 59 && (unsigned)buf[2]==221) { LCD_digit[0]=5; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]== 91 && (unsigned)buf[2]==221) { LCD_digit[0]=6; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]==251 && (unsigned)buf[2]== 13) { LCD_digit[0]=7; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]== 91 && (unsigned)buf[2]== 93) { LCD_digit[0]=8; LCD_decimal[0]=1; }
    if ((unsigned)buf[0]== 59 && (unsigned)buf[2]== 93) { LCD_digit[0]=9; LCD_decimal[0]=1; }

	// LCD annunciators

	//         M            Hz
	//      DC REL          V  
	//      AC HOLD m oC u  A  
	// buf  1  4    8 11 12 13

	if ((unsigned)(buf[ 1]& 16)) LCD_DC   = 1; // DC
	if ((unsigned)buf[13]== 140) LCD_V    = 1; // Volts
	if ((unsigned)buf[13]== 124) LCD_A    = 1; // Amps
	if ((unsigned)buf[ 8]== 134) LCD_m    = 1; // m - milliamps
	if ((unsigned)buf[12]== 126) LCD_u    = 1; // u - microamps
	if ((unsigned)buf[ 4]== 177) LCD_REL  = 1; // REL
	if ((unsigned)buf[ 4]== 241) LCD_HOLD = 1; // HOLD
	if ((unsigned)buf[13]== 172) LCD_Hz   = 1; // Hz
	if ((unsigned)buf[11]== 191) LCD_oC   = 1; // degrees C
	if ((unsigned)buf[ 4]== 145) LCD_M    = 1; // Mega - ohms

	// printf DMM output to display .. only print leading decimal-point!

	if (LCD_OL==1) { // overload
 	  printf(" 0L - DMM Overloaded, change range setting"); 
	}
	else { // normal operation
     (LCD_minus==1)      ? printf("-"):printf(" ");
      printf("%d",LCD_digit[3]);
      //printf(" [%d,%d] ",buf[3],buf[10]); // digit 3

      (LCD_decimal[2]==1) ? printf("."):printf("");
      printf("%d",LCD_digit[2]);
	  //printf(" [%d,%d] ",buf[6],buf[ 9]); // digit 2

      (LCD_decimal[1]==1) ? printf("."):printf("");
      printf("%d",LCD_digit[1]);
	  //printf(" [%d,%d] ",buf[5],buf[ 7]); // digit 1

      (LCD_decimal[0]==1) ? printf("."):printf("");
      printf("%d",LCD_digit[0]);
	  //printf(" [%d,%d] ",buf[0],buf[ 2]); // digit 0
	}

	printf(" ");
    if (LCD_m)    printf("m"); // m - milliamps
    if (LCD_u)    printf("u"); // u - microamps
    if (LCD_V)    printf("V"); // Volts
    if (LCD_A)    printf("A"); // Amps
    if (LCD_oC)   printf("oC"); // degrees C
    if (LCD_M)    printf("Mohms"); // Mega - ohms
    if (LCD_Hz)   printf("Hz"); // Hz

	printf(" ");
 	if ((LCD_V || LCD_A)) (LCD_DC==1) ? printf("DC") : printf("AC"); // AC/DC

	printf(" ");
    if (LCD_REL)  printf("REL"); // REL
    if (LCD_HOLD) printf("HOLD"); // HOLD

	//printf(" buf[%d,%d,%d,%d,%d,%d,%d,%d] ",buf[1],buf[4],buf[8],buf[11],buf[12],buf[13],buf[14],buf[15]); // ?

	return DMM;
  }

} // decode_Victor86B()


void display_buffer(unsigned char* buf) {
  printf("\n");  
  printf("%d,%d, ",buf[3],buf[10]); // digit 3
  printf("%d,%d, ",buf[6],buf[ 9]); // digit 2
  printf("%d,%d, ",buf[5],buf[ 7]); // digit 1
  printf("%d,%d, ",buf[0],buf[ 2]); // digit 0
  printf("%d,%d, ",buf[1],buf[ 4]); // ?
  printf("\n");
} // display_buffer()


int main(int argc, char* argv[]) {

	int res;
	unsigned char buf[256];
	hid_device *handle;
	int read=0;
	clock_t ticks1, ticks2;


	//report_HIDs(); // report attached USB HIDs to screen

	handle = hid_open(0x1244, 0xd237, NULL);
	if (!handle) {
	  printf("Victor86B DMM not found - \n  PLUG in USB cable and ensure yellow RS232 button on DMM is set\n");
 	  //return 1;
	}
	else {
	  printf("found Victor86B DMM\n");
	}

	// while (read<10) {
	while (1) {  // read out data from DMM over USB
	  
	  ticks1=clock(); // start-time

	  res = 0;
	  while (res == 0) {
	    res = hid_read(handle, buf, sizeof(buf));
	    if (res == 0) printf("waiting...\n");
	    if (res  < 0) printf("Unable to read()\n");
	  }

	  // measure time take to read data from DMM

	  ticks2=clock()-ticks1; // elapsed time
	  //printf("%ld,",ticks2);
	  //printf("%2.2fsec,",(double)CLOCKS_PER_SEC/(double)ticks2);

	  decode_Victor86B(buf);	  
	  printf("\n");
      read++;

	} // while()

    while (1); //

	hid_close(handle);
	hid_exit();
	 
	return 0;

} // main()


// Victor86B_usbDMM.cpp